using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class MicroCoreTable
    {
        public Dictionary<string, MicroCoreOp> Ops = new Dictionary<string,MicroCoreOp>();
        public Dictionary<string,int> StatusBits = new Dictionary<string,int>();
        public Dictionary<string, int> ControlStates = new Dictionary<string,int>();
        public Dictionary<string,int> Labels = new Dictionary<string,int>();
        int iCurrentAddress = 0;
        public Dictionary<int, int> ROM = new Dictionary<int,int>();

        int iWidth;

        public MicroCoreOp AddOp(string sOpName)
        {
            MicroCoreOp oOp = new MicroCoreOp(this,sOpName);
            Ops.Add(sOpName, oOp);
            return oOp;
        }

        public int Width
        {
            get { return iWidth; }
        }

        internal int StatusBitToCode(string psStatusBit)
        {
            if (StatusBits.ContainsKey(psStatusBit))
                return StatusBits[psStatusBit];
            int iCode = StatusBits.Count;
            StatusBits.Add(psStatusBit,iCode);
            return iCode;
        }

        internal int ControlStateToCode(string psCode)
        {
            if (ControlStates.ContainsKey(psCode))
                return ControlStates[psCode];
            int iCode = ControlStates.Count;
            ControlStates.Add(psCode, iCode);
            return iCode;
        }

        internal int NextAddress()
        {
            return NextAddress("");
        }

        internal int NextAddress(string psLabel)
        {
            iCurrentAddress++;
            if (Labels.ContainsKey(psLabel))
            {
                throw new Exception("Label named " + psLabel + " already exists.");
            }
            if (psLabel != "")
                Labels.Add(psLabel,iCurrentAddress);
            return iCurrentAddress;
        }

        internal int LabelToAddress(string psLabel)
        {
            if (!Labels.ContainsKey(psLabel))
                throw new Exception("Label : {" + psLabel + "} does not exist.");
            return Labels[psLabel];
        }

        internal void DefineROM(int piAddress, int piValue)
        {
            ROM.Add(piAddress, piValue);
        }

        public void CompileROM()
        {
            CompileROM(0);
        }

        public void CompileROM(int piWidth)
        {
            iWidth = piWidth;

            int iLargestValue = 0;
            foreach (MicroCoreOp oOp in Ops.Values)
            {
                oOp.Compile();
            }
            foreach (MicroCoreOp oOp in Ops.Values)
            {
                int iLargestOpValue = oOp.PostCompile();
                if (iLargestOpValue > iLargestValue)
                    iLargestValue = iLargestOpValue;
            }
            int iMinWidth = Conversion.MinBitWidth(iLargestValue) + 2;
            if (iWidth < 1)
                iWidth = iMinWidth;
            else
            {
                if (iWidth < iMinWidth)
                    throw new Exception("ROM width needs to be at least " + iMinWidth.ToString() + " bits.");
            }
            ROM.Clear();
            foreach (MicroCoreOp oOp in Ops.Values)
            {
                oOp.WriteROMTable(iWidth-2);
            }

           ReportContents(); //here here
        }

        public string ReportContents()
        {
            string sResult = "";
            
            foreach (MicroCoreOp oOp in Ops.Values)
            {
                sResult += oOp.ReportContents() + "\n";
            }
            Console.WriteLine(sResult);
            return sResult;
        }


    }
}
